
#include "Common.h"
#include "IoService.h"
#include "Timer.h"

namespace fx {

    Timer::Timer(boost::uint32_t interval_in_ms, boost::uint32_t max_timer_count)
        : interval_in_ms_(interval_in_ms)
        , max_timer_count_(max_timer_count)
        , curr_timer_count_(0)
        , internal_timer_(IoService::IOS())
    {
    }

    TimerPtr Timer::Create(
        boost::uint32_t interval_in_ms, boost::uint32_t max_timer_count) 
    {
        TimerPtr timer(new Timer(interval_in_ms, max_timer_count));
        return timer;
    }
    void Timer::Start() {
        curr_timer_count_ = 0;
        StartLocalTimer();
    }
    void Timer::Stop() {
        boost::system::error_code error;
        internal_timer_.cancel(error);
    }

    void Timer::SetIntervalInMS(boost::uint32_t interval_in_ms) {
        interval_in_ms_ = interval_in_ms;
    }
    boost::uint32_t Timer::GetIntervalInMS() const {
        return interval_in_ms_;
    }

    void Timer::SetMaxTimerCount(boost::uint32_t max_timer_count) {
        max_timer_count_ = max_timer_count;
    }
    boost::uint32_t Timer::GetMaxTimerCount() const {
        return max_timer_count_;
    }

    Timer::connection_t Timer::AddTimerHandler(handler_t handler) {
        return timer_signal_.connect( handler );
    }

    void Timer::StartLocalTimer() {
        // increament
        ++curr_timer_count_;
        // timer
        internal_timer_.expires_from_now(boost::posix_time::milliseconds(interval_in_ms_));
        internal_timer_.async_wait(boost::bind(
            &Timer::OnTimerElapsed, shared_from_this(), boost::asio::placeholders::error
            ));
    }

    void Timer::OnTimerElapsed(const boost::system::error_code& error) {
        if (!error) {
            // timer event
            timer_signal_(curr_timer_count_);
            // stop or continue
            if (curr_timer_count_ == max_timer_count_) {
                Stop();
            }
            else {
                StartLocalTimer();
            }
        }
        else {
            Stop();
        }
    }

}
